package com.songlanyun.modules.order.service.impl.coupon.platformcoupon;

import com.songlanyun.common.utils.custom.MathUtils;
import com.songlanyun.modules.coupon.model.vo.CouponEntityVo;
import com.songlanyun.modules.coupon.model.vo.CouponReceiveRecordVo;
import com.songlanyun.modules.coupon.service.CouponReceiveRecordService;
import com.songlanyun.modules.coupon.service.CouponService;
import com.songlanyun.modules.order.model.dto.SubmitOrderUseCoupon;
import com.songlanyun.modules.order.model.vo.SubmitChildOrderVo;
import com.songlanyun.modules.order.model.vo.SubmitOrderVo;
import com.songlanyun.modules.order.model.vo.SubmitShopOrderVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service("commonOrderUsePlatformCouponService")
public class CommonOrderUsePlatformCouponImpl implements IUsePlatformCouponService {

    @Autowired
    private CouponReceiveRecordService couponReceiveRecordService;

    @Autowired
    private CouponService couponService;

    @Override
    public SubmitOrderVo handlePlatformCoupon(Long userId, SubmitOrderVo submitOrderVo) {
        /**
         * 查出我领取的平台券,
         * 1、可以使用的，
         * 2、按面额排倒倒叙面额大的排前面，
         * 3、按门槛值排正序，门槛低的排前面，
         * 4、按通用券排正序，通用券排进面
         */
        if (submitOrderVo.getPlatformCoupon().getMyCouponId() == 0L) {
            /**
             * 系统取优惠券
             */
            List<CouponReceiveRecordVo> couponEntityVos = couponReceiveRecordService.loadMyPlatCoupons(userId);
            for (CouponReceiveRecordVo couponEntityVo : couponEntityVos) {
                if (handle(submitOrderVo, couponEntityVo)) {
                    return submitOrderVo;
                }
            }
        } else {
            /**
             * 手动取优惠券
             */
            CouponReceiveRecordVo couponEntityVo = couponReceiveRecordService.loadByCouponSlimEntity(submitOrderVo.getPlatformCoupon().getMyCouponId(), true);
            handle(submitOrderVo, couponEntityVo);
        }
        return submitOrderVo;
    }

    private boolean handle(SubmitOrderVo submitOrderVo, CouponReceiveRecordVo couponEntityVo) {
        switch (submitOrderVo.getMarketingType())
        {
            case 1:
                if(!couponEntityVo.isAdaptSecKill())
                {
                    return false;
                }
                break;
            case 2:
                if(!couponEntityVo.isAdaptGroupBuy())
                {
                    return false;
                }
                break;
            default:
                break;
        }
        if (couponEntityVo.getUniversal()) {
            if (generalCouponHandle(couponEntityVo, submitOrderVo)) {
                return true;
            }
        } else {
            if (notGeneralCouponHandle(couponEntityVo, submitOrderVo)) {
                return true;
            }
        }
        return false;


    }


    /**
     * 通用券算法
     *
     * @param couponEntityVo
     * @param submitOrderVo
     * @return
     */
    private Boolean generalCouponHandle(CouponReceiveRecordVo couponEntityVo, SubmitOrderVo submitOrderVo) {
        if (!couponEntityVo.getHasThreshold()) {
            return noHasThresholdGeneral(couponEntityVo, submitOrderVo);
        } else {
            return hasThresholdGeneral(couponEntityVo, submitOrderVo);
        }
    }

    /**
     * 非通用券算法
     *
     * @param couponEntityVo
     * @param submitOrderVo
     * @return
     */
    private Boolean notGeneralCouponHandle(CouponReceiveRecordVo couponEntityVo, SubmitOrderVo submitOrderVo) {
        if (!couponEntityVo.getHasThreshold()) {
            return noHasThresholdNotGeneral(couponEntityVo, submitOrderVo);
        } else {
            return hasThresholdNotGeneral(couponEntityVo, submitOrderVo);
        }
    }


    /**
     * 无门槛的通用算法
     *
     * @param couponEntityVo
     * @param submitOrderVo
     * @return
     */
    private Boolean noHasThresholdGeneral(CouponReceiveRecordVo couponEntityVo, SubmitOrderVo submitOrderVo) {
        childOrderSharingCompute(couponEntityVo, submitOrderVo, submitOrderVo.getShopOrders(), submitOrderVo.getTotalMoneyNoFreight());
        return true;
    }


    /**
     * 有门槛的通用券算法
     *
     * @param couponEntityVo
     * @param submitOrderVo
     * @return
     */
    private Boolean hasThresholdGeneral(CouponReceiveRecordVo couponEntityVo, SubmitOrderVo submitOrderVo) {
        if (submitOrderVo.getTotalMoneyNoFreight().compareTo(couponEntityVo.getThreshold()) < 0) {
            return false;
        }
        return noHasThresholdGeneral(couponEntityVo, submitOrderVo);
    }


    /**
     * 无门槛的非通用券算算法
     *
     * @param couponEntityVo
     * @param submitOrderVo
     * @return
     */
    private Boolean noHasThresholdNotGeneral(CouponReceiveRecordVo couponEntityVo, SubmitOrderVo submitOrderVo) {
        List<SubmitShopOrderVo> adaptOrderVos = new ArrayList<>();

        BigDecimal totalAmount = getTotalOrderAmount(couponEntityVo,submitOrderVo,adaptOrderVos);
        if(totalAmount.compareTo(BigDecimal.ZERO)==0)
        {
            return false;
        }
        childOrderSharingCompute(couponEntityVo, submitOrderVo, adaptOrderVos, totalAmount);
        return true;
    }

    /**
     * 有门槛的非通用券算法
     *
     * @param couponEntityVo
     * @param submitOrderVo
     * @return
     */
    private Boolean hasThresholdNotGeneral(CouponReceiveRecordVo couponEntityVo, SubmitOrderVo submitOrderVo) {

        List<SubmitShopOrderVo> adaptOrderVos = new ArrayList<>();
        BigDecimal totalAmount = getTotalOrderAmount(couponEntityVo,submitOrderVo,adaptOrderVos);
        if(totalAmount.compareTo(BigDecimal.ZERO)==0)
        {
            return false;
        }

        if (totalAmount.compareTo(couponEntityVo.getThreshold()) < 0) {
            return false;
        }
        childOrderSharingCompute(couponEntityVo, submitOrderVo, adaptOrderVos, totalAmount);
        return true;
    }


    private BigDecimal getTotalOrderAmount(CouponReceiveRecordVo couponEntityVo, SubmitOrderVo submitOrderVo,List<SubmitShopOrderVo> adaptOrderVos)
    {
        Map<Long, SubmitShopOrderVo> shopOrderGroups = submitOrderVo.getShopOrders().stream().collect(Collectors.toMap(SubmitShopOrderVo::getShopId, vo -> vo));
        Set<Long> shopIds = shopOrderGroups.keySet();
        List<Long> adaptShopIds = couponEntityVo.loadAdaptShopIds();
        if (couponEntityVo.getAdaptOrNo()) {
            shopIds.retainAll(adaptShopIds);

        } else {
            shopIds.removeAll(adaptShopIds);
        }

        BigDecimal totalAmount = BigDecimal.ZERO;
        for (Long shopId : shopIds) {
            SubmitShopOrderVo submitShopOrderVo = shopOrderGroups.get(shopId);
            adaptOrderVos.add(submitShopOrderVo);
            totalAmount = MathUtils.add(submitShopOrderVo.getTotalAmountNoFreight(), totalAmount);
        }
        return totalAmount;
    }



    private void childOrderSharingCompute(CouponReceiveRecordVo couponEntityVo, SubmitOrderVo submitOrderVo, List<SubmitShopOrderVo> adaptOrderVos, BigDecimal totalAmount) {
        BigDecimal faceValue = couponEntityVo.getFaceValue();
        BigDecimal resultCouponValue = faceValue;
        boolean isExceed = false;
        if (faceValue.compareTo(totalAmount) >= 0) {
            resultCouponValue = totalAmount;
            isExceed = true;
        }
        /**
         * 计算店铺优惠券的总情况
         */
        submitOrderVo.setPlatformCoupon(SubmitOrderUseCoupon.builder()
                .myCouponId(couponEntityVo.getId())
                .couponId(couponEntityVo.getCouponId())
                .couponName(couponEntityVo.getName())
                .couponFaceValue(couponEntityVo.getFaceValue())
                .couponResultValue(resultCouponValue)
                .build());


        if (isExceed) {
            for (SubmitShopOrderVo shopOrderVo : adaptOrderVos) {
                shopOrderVo.setPlatformCouponSharing(shopOrderVo.getTotalAmountDecShopCoupon());
                shopOrderVo.setTotalAmountNoFreight(BigDecimal.ZERO);
                shopOrderVo.setTotalAmount(shopOrderVo.getTotalFreight());
                shopOrderVo.setTotalReduced(MathUtils.add(shopOrderVo.getTotalReduced(),shopOrderVo.getPlatformCouponSharing()));
                setPlatformCoupon(couponEntityVo, shopOrderVo);

                childOrderSharingPlatform(shopOrderVo,shopOrderVo.getPlatformCouponSharing());
            }
        } else {
            BigDecimal sum = BigDecimal.ZERO;
            if (adaptOrderVos.size() > 1) {
                for (SubmitShopOrderVo shopOrderVo : adaptOrderVos) {
                    BigDecimal temp = MathUtils.setScaleDown(shopOrderVo.getTotalAmountNoFreight().doubleValue() * faceValue.doubleValue() / totalAmount.doubleValue());
                    sum = MathUtils.add(temp, sum);
                    shopOrderVo.setPlatformCouponSharing(temp);
                }
                if (faceValue.compareTo(sum) > 0) {
                    BigDecimal value = MathUtils.subtract(faceValue, sum);
                    adaptOrderVos.get(0).setPlatformCouponSharing(MathUtils.add(adaptOrderVos.get(0).getPlatformCouponSharing(), value));
                }

                for(SubmitShopOrderVo shopOrderVo : adaptOrderVos)
                {
                    shopOrderVo.setTotalAmountNoFreight(MathUtils.subtract(shopOrderVo.getTotalAmountNoFreight(),shopOrderVo.getPlatformCouponSharing()));
                    shopOrderVo.setTotalAmount(MathUtils.add(shopOrderVo.getTotalAmountNoFreight() ,shopOrderVo.getTotalFreight()));
                    shopOrderVo.setTotalReduced(MathUtils.add(shopOrderVo.getTotalReduced(),shopOrderVo.getPlatformCouponSharing()));

                    setPlatformCoupon(couponEntityVo, shopOrderVo);
                    childOrderSharingPlatform(shopOrderVo,shopOrderVo.getPlatformCouponSharing());
                }


            } else {
                SubmitShopOrderVo submitShopOrderVo = adaptOrderVos.get(0);
                submitShopOrderVo.setPlatformCouponSharing(faceValue);
                setPlatformCoupon(couponEntityVo, submitShopOrderVo);
                childOrderSharingPlatform(submitShopOrderVo,submitShopOrderVo.getPlatformCouponSharing());

                submitShopOrderVo.setTotalAmountNoFreight(MathUtils.subtract(submitShopOrderVo.getTotalAmountNoFreight(),submitShopOrderVo.getPlatformCouponSharing()));
                submitShopOrderVo.setTotalAmount(MathUtils.add(submitShopOrderVo.getTotalAmountNoFreight() ,submitShopOrderVo.getTotalFreight()));
                submitShopOrderVo.setTotalReduced(MathUtils.add(submitShopOrderVo.getTotalReduced(),submitShopOrderVo.getPlatformCouponSharing()));
            }
        }
    }

    private void setPlatformCoupon(CouponReceiveRecordVo couponEntityVo, SubmitShopOrderVo shopOrderVo) {
        shopOrderVo.setPlatformCoupon(SubmitOrderUseCoupon.builder()
                .myCouponId(couponEntityVo.getId())
                .couponId(couponEntityVo.getCouponId())
                .couponName(couponEntityVo.getName())
                .couponFaceValue(couponEntityVo.getFaceValue())
                .couponResultValue(shopOrderVo.getPlatformCouponSharing())
                .build());
    }

    private void  childOrderSharingPlatform(SubmitShopOrderVo shopOrderVo,BigDecimal orderPlatformCouponSharing)
    {
        List<SubmitChildOrderVo> items = shopOrderVo.getItems();
        BigDecimal sum = BigDecimal.ZERO;
        for(SubmitChildOrderVo submitChildOrderVo : items)
        {
            BigDecimal goodsAmount = MathUtils.subtractMulti(submitChildOrderVo.getTotalPrice(),submitChildOrderVo.getFirstOrderReduced(), submitChildOrderVo.getShopCouponSharing());
            if(shopOrderVo.getTotalAmountNoFreight().compareTo(BigDecimal.ZERO)==0)
            {
                submitChildOrderVo.setPlatformCouponSharing(goodsAmount);
                sum = MathUtils.add(submitChildOrderVo.getPlatformCouponSharing(), sum);
            }
            else
            {
                submitChildOrderVo.setPlatformCouponSharing(MathUtils.setScale(goodsAmount.doubleValue() * orderPlatformCouponSharing.doubleValue() / shopOrderVo.getTotalAmountDecShopCoupon().doubleValue()));
                sum = MathUtils.add(submitChildOrderVo.getPlatformCouponSharing(), sum);
            }

        }
        if (orderPlatformCouponSharing.compareTo(sum) > 0) {
            BigDecimal value = MathUtils.subtract(orderPlatformCouponSharing, sum);
            items.get(0).setPlatformCouponSharing(MathUtils.add(items.get(0).getPlatformCouponSharing(), value));
        }

    }


}
